import tkinter as tk
from tkinter import filedialog, messagebox, simpledialog, ttk
import os
import re
from tkinter.scrolledtext import ScrolledText
import tkinter.font as tkfont

class NotePad:
    def __init__(self, root):
        self.root = root
        self.root.title("增强版记事本")
        self.root.geometry("1000x700")
        self.root.config(bg='#F0F0F0')  # 设置主窗口背景色
        
        # 剪贴板历史记录
        self.clipboard_history = []
        self.max_clipboard_items = 10  # 最多保存10条剪贴板历史
        
        # 撤销/重做最大步数
        self.max_undo_steps = 100
        
        # 当前查找参数
        self.find_pattern = ""
        self.match_case = False
        self.find_pos = tk.END
        
        # 初始化字体和颜色设置
        self.current_font = ("SimHei", 12, "normal")  # 字体名、大小、样式
        self.current_fg_color = "black"               # 文本前景色
        self.current_bg_color = "white"               # 文本背景色
        
        # 文本编辑区域，支持撤销/重做和列选模式
        self.text_area = ScrolledText(
            self.root, 
            undo=True,
            maxundo=self.max_undo_steps,
            wrap=tk.WORD,
            font=self.current_font,
            fg=self.current_fg_color,
            bg=self.current_bg_color,
            relief=tk.SUNKEN,
            bd=2
        )
        # 支持列选模式 (按住Alt键拖动)
        self.text_area.bind("<Alt-ButtonPress-1>", self.start_column_select)
        self.text_area.bind("<Alt-B1-Motion>", self.update_column_select)
        self.text_area.pack(expand=True, fill=tk.BOTH, padx=5, pady=5)
        
        # 当前文件路径
        self.current_file = None
        # 是否已保存
        self.saved = True
        
        # 创建菜单
        self.create_menu()
        
        # 绑定文本变化事件和快捷键
        self.bind_events()

    def create_menu(self):
        menubar = tk.Menu(self.root)
        
        # 文件菜单
        file_menu = tk.Menu(menubar, tearoff=0)
        file_menu.add_command(label="新建空白笔记", command=self.new_note, accelerator="Ctrl+N")
        file_menu.add_command(label="新建模板笔记", command=self.new_template_note)
        file_menu.add_separator()
        file_menu.add_command(label="打开笔记", command=self.open_note, accelerator="Ctrl+O")
        file_menu.add_separator()
        file_menu.add_command(label="保存", command=self.save_note, accelerator="Ctrl+S")
        file_menu.add_command(label="另存为", command=self.save_note_as)
        file_menu.add_separator()
        file_menu.add_command(label="退出", command=self.exit_app, accelerator="Ctrl+Q")
        
        # 编辑菜单
        edit_menu = tk.Menu(menubar, tearoff=0)
        # 撤销/重做子菜单
        undo_redo_menu = tk.Menu(edit_menu, tearoff=0)
        undo_redo_menu.add_command(label="撤销", command=self.undo, accelerator="Ctrl+Z")
        undo_redo_menu.add_command(label="重做", command=self.redo, accelerator="Ctrl+Y")
        edit_menu.add_cascade(label="撤销/重做", menu=undo_redo_menu)
        edit_menu.add_separator()
        
        # 剪贴板子菜单
        clipboard_menu = tk.Menu(edit_menu, tearoff=0)
        clipboard_menu.add_command(label="剪切", command=self.cut_text, accelerator="Ctrl+X")
        clipboard_menu.add_command(label="复制", command=self.copy_text, accelerator="Ctrl+C")
        clipboard_menu.add_command(label="粘贴", command=self.paste_text, accelerator="Ctrl+V")
        clipboard_menu.add_separator()
        clipboard_menu.add_command(label="剪贴板历史", command=self.show_clipboard_history)
        edit_menu.add_cascade(label="剪贴板操作", menu=clipboard_menu)
        edit_menu.add_separator()
        
        # 选择子菜单
        select_menu = tk.Menu(edit_menu, tearoff=0)
        select_menu.add_command(label="全选", command=self.select_all, accelerator="Ctrl+A")
        select_menu.add_command(label="列选模式", command=self.show_column_select_help)
        edit_menu.add_cascade(label="选择", menu=select_menu)
        edit_menu.add_separator()
        
        # 查找替换
        edit_menu.add_command(label="查找/替换", command=self.show_find_replace, accelerator="Ctrl+F")
        
        # 格式菜单
        format_menu = tk.Menu(menubar, tearoff=0)
        # 文本样式子菜单
        style_menu = tk.Menu(format_menu, tearoff=0)
        style_menu.add_command(label="加粗", command=lambda: self.apply_format("bold"), accelerator="Ctrl+B")
        style_menu.add_command(label="斜体", command=lambda: self.apply_format("italic"), accelerator="Ctrl+I")
        style_menu.add_command(label="下划线", command=lambda: self.apply_format("underline"), accelerator="Ctrl+U")
        style_menu.add_command(label="删除线", command=lambda: self.apply_format("overstrike"))
        format_menu.add_cascade(label="文本样式", menu=style_menu)
        format_menu.add_separator()
        
        # 字体设置
        font_menu = tk.Menu(format_menu, tearoff=0)
        font_menu.add_command(label="字体设置", command=self.set_font)
        font_menu.add_command(label="颜色设置", command=self.set_color)
        format_menu.add_cascade(label="字体与颜色", menu=font_menu)
        
        menubar.add_cascade(label="文件", menu=file_menu)
        menubar.add_cascade(label="编辑", menu=edit_menu)
        menubar.add_cascade(label="格式", menu=format_menu)
        self.root.config(menu=menubar)

    def bind_events(self):
        """绑定事件和快捷键"""
        # 文本变化事件
        self.text_area.bind("<Key>", self.on_text_change)
        
        # 快捷键绑定
        self.root.bind("<Control-n>", lambda event: self.new_note())
        self.root.bind("<Control-o>", lambda event: self.open_note())
        self.root.bind("<Control-s>", lambda event: self.save_note())
        self.root.bind("<Control-q>", lambda event: self.exit_app())
        self.root.bind("<Control-z>", lambda event: self.undo())
        self.root.bind("<Control-y>", lambda event: self.redo())
        self.root.bind("<Control-x>", lambda event: self.cut_text())
        self.root.bind("<Control-c>", lambda event: self.copy_text())
        self.root.bind("<Control-v>", lambda event: self.paste_text())
        self.root.bind("<Control-a>", lambda event: self.select_all())
        self.root.bind("<Control-f>", lambda event: self.show_find_replace())
        self.root.bind("<Control-b>", lambda event: self.apply_format("bold"))
        self.root.bind("<Control-i>", lambda event: self.apply_format("italic"))
        self.root.bind("<Control-u>", lambda event: self.apply_format("underline"))

    def show_column_select_help(self):
        """显示列选模式帮助信息"""
        messagebox.showinfo("列选模式", "列选模式：按住Alt键并拖动鼠标即可垂直选择文本，适合编辑表格或代码。")

    # 基础编辑工具实现
    def undo(self):
        """撤销操作"""
        try:
            self.text_area.edit_undo()
            self.saved = False
        except tk.TclError:
            pass  # 没有可撤销的操作

    def redo(self):
        """重做操作"""
        try:
            self.text_area.edit_redo()
            self.saved = False
        except tk.TclError:
            pass  # 没有可重做的操作

    def cut_text(self):
        """剪切选中的文本"""
        try:
            # 获取选中的文本
            selected_text = self.text_area.get(tk.SEL_FIRST, tk.SEL_LAST)
            # 保存到剪贴板历史
            if selected_text:
                self.add_to_clipboard_history(selected_text)
            # 执行剪切
            self.text_area.event_generate("<<Cut>>")
            self.saved = False
        except tk.TclError:
            messagebox.showinfo("提示", "没有选中的文本")

    def copy_text(self):
        """复制选中的文本"""
        try:
            # 获取选中的文本
            selected_text = self.text_area.get(tk.SEL_FIRST, tk.SEL_LAST)
            # 保存到剪贴板历史
            if selected_text:
                self.add_to_clipboard_history(selected_text)
            # 执行复制
            self.text_area.event_generate("<<Copy>>")
        except tk.TclError:
            messagebox.showinfo("提示", "没有选中的文本")

    def paste_text(self):
        """粘贴文本"""
        self.text_area.event_generate("<<Paste>>")
        self.saved = False

    def add_to_clipboard_history(self, text):
        """添加文本到剪贴板历史"""
        # 避免重复添加相同内容
        if self.clipboard_history and self.clipboard_history[0] == text:
            return
            
        # 添加到历史记录开头
        self.clipboard_history.insert(0, text)
        
        # 保持历史记录长度不超过最大值
        if len(self.clipboard_history) > self.max_clipboard_items:
            self.clipboard_history = self.clipboard_history[:self.max_clipboard_items]

    def show_clipboard_history(self):
        """显示剪贴板历史记录"""
        if not self.clipboard_history:
            messagebox.showinfo("剪贴板历史", "剪贴板为空")
            return
            
        # 创建剪贴板历史窗口
        history_window = tk.Toplevel(self.root)
        history_window.title("剪贴板历史")
        history_window.geometry("400x300")
        history_window.transient(self.root)
        history_window.grab_set()
        
        # 创建列表框显示历史记录
        listbox = tk.Listbox(history_window, selectmode=tk.SINGLE)
        listbox.pack(expand=True, fill=tk.BOTH, padx=5, pady=5)
        
        # 添加历史记录到列表框
        for i, item in enumerate(self.clipboard_history):
            # 限制显示长度
            display_text = item[:50] + ("..." if len(item) > 50 else "")
            listbox.insert(tk.END, f"{i+1}. {display_text}")
        
        # 双击条目粘贴
        def paste_selected(event):
            index = listbox.curselection()
            if index:
                text = self.clipboard_history[index[0]]
                self.text_area.insert(tk.INSERT, text)
                self.saved = False
                history_window.destroy()
        
        listbox.bind("<Double-1>", paste_selected)
        
        # 按钮
        btn_frame = ttk.Frame(history_window)
        btn_frame.pack(fill=tk.X, padx=5, pady=5)
        
        ttk.Button(btn_frame, text="粘贴选中", 
                  command=lambda: paste_selected(None)).pack(side=tk.LEFT, padx=5)
        ttk.Button(btn_frame, text="清空历史", 
                  command=lambda: [self.clipboard_history.clear(), history_window.destroy()]).pack(side=tk.RIGHT, padx=5)

    def select_all(self):
        """全选文本"""
        self.text_area.tag_add(tk.SEL, "1.0", tk.END)
        self.text_area.mark_set(tk.INSERT, "1.0")
        self.text_area.see(tk.INSERT)
        return 'break'

    def start_column_select(self, event):
        """开始列选模式"""
        self.text_area.tag_remove("sel", "1.0", tk.END)
        self.start_row = self.text_area.index(f"@{event.x},{event.y}").split('.')[0]
        self.start_col = self.text_area.index(f"@{event.x},{event.y}").split('.')[1]
        self.text_area.mark_set("insert", f"@{event.x},{event.y}")
        return "break"

    def update_column_select(self, event):
        """更新列选区域"""
        self.text_area.tag_remove("sel", "1.0", tk.END)
        end_pos = self.text_area.index(f"@{event.x},{event.y}")
        end_row = end_pos.split('.')[0]
        end_col = end_pos.split('.')[1]
        
        # 确定列选范围
        start_row = min(int(self.start_row), int(end_row))
        end_row = max(int(self.start_row), int(end_row))
        start_col = min(int(self.start_col), int(end_col))
        end_col = max(int(self.start_col), int(end_col))
        
        # 选中列区域
        for row in range(start_row, end_row + 1):
            self.text_area.tag_add("sel", f"{row}.{start_col}", f"{row}.{end_col}")
        return "break"

    # 查找与替换功能实现
    def show_find_replace(self):
        """显示查找替换对话框"""
        # 创建对话框
        find_window = tk.Toplevel(self.root)
        find_window.title("查找与替换")
        find_window.geometry("400x200")
        find_window.transient(self.root)
        find_window.resizable(False, False)
        
        # 创建控件
        ttk.Label(find_window, text="查找内容:").grid(row=0, column=0, sticky=tk.W, padx=5, pady=5)
        find_entry = ttk.Entry(find_window, width=30)
        find_entry.grid(row=0, column=1, padx=5, pady=5)
        find_entry.focus_set()
        
        ttk.Label(find_window, text="替换为:").grid(row=1, column=0, sticky=tk.W, padx=5, pady=5)
        replace_entry = ttk.Entry(find_window, width=30)
        replace_entry.grid(row=1, column=1, padx=5, pady=5)
        
        # 匹配大小写复选框
        match_case_var = tk.BooleanVar(value=self.match_case)
        match_case_check = ttk.Checkbutton(find_window, text="匹配大小写", variable=match_case_var)
        match_case_check.grid(row=2, column=0, columnspan=2, sticky=tk.W, padx=5)
        
        # 按钮区域
        btn_frame = ttk.Frame(find_window)
        btn_frame.grid(row=3, column=0, columnspan=2, pady=10)
        
        # 查找下一个按钮
        def find_next():
            self.match_case = match_case_var.get()
            self.find_pattern = find_entry.get()
            if not self.find_pattern:
                messagebox.showinfo("提示", "请输入查找内容")
                return
                
            self.find_text()
        
        # 替换按钮
        def replace():
            self.match_case = match_case_var.get()
            self.find_pattern = find_entry.get()
            replace_text = replace_entry.get()
            
            if not self.find_pattern:
                messagebox.showinfo("提示", "请输入查找内容")
                return
                
            # 检查是否有选中的匹配项
            try:
                selected_text = self.text_area.get(tk.SEL_FIRST, tk.SEL_LAST)
                if selected_text == self.find_pattern or (not self.match_case and selected_text.lower() == self.find_pattern.lower()):
                    self.text_area.delete(tk.SEL_FIRST, tk.SEL_LAST)
                    self.text_area.insert(tk.SEL_FIRST, replace_text)
                    self.saved = False
            except tk.TclError:
                pass
                
            # 查找下一个
            self.find_text()
        
        # 全部替换按钮
        def replace_all():
            self.match_case = match_case_var.get()
            self.find_pattern = find_entry.get()
            replace_text = replace_entry.get()
            
            if not self.find_pattern:
                messagebox.showinfo("提示", "请输入查找内容")
                return
                
            # 从开头开始查找
            self.find_pos = "1.0"
            count = 0
            
            # 循环查找并替换所有匹配项
            while True:
                result = self.find_text(automatic=True)
                if not result:
                    break
                    
                # 替换找到的文本
                self.text_area.delete(tk.SEL_FIRST, tk.SEL_LAST)
                self.text_area.insert(tk.SEL_FIRST, replace_text)
                self.saved = False
                count += 1
                self.find_pos = tk.SEL_FIRST  # 从替换后的位置继续查找
                
            messagebox.showinfo("替换完成", f"共替换了 {count} 处匹配")
        
        ttk.Button(btn_frame, text="查找下一个", command=find_next).pack(side=tk.LEFT, padx=5)
        ttk.Button(btn_frame, text="替换", command=replace).pack(side=tk.LEFT, padx=5)
        ttk.Button(btn_frame, text="全部替换", command=replace_all).pack(side=tk.LEFT, padx=5)
        ttk.Button(btn_frame, text="取消", command=find_window.destroy).pack(side=tk.LEFT, padx=5)

    def find_text(self, automatic=False):
        """查找文本并高亮显示"""
        # 清除之前的选中
        self.text_area.tag_remove(tk.SEL, "1.0", tk.END)
        
        if not self.find_pattern:
            return False
            
        # 获取文本内容
        text_content = self.text_area.get("1.0", tk.END)
        
        # 确定查找的起始位置
        start_pos = self.find_pos if self.find_pos != tk.END else "1.0"
        
        # 根据是否匹配大小写调整搜索模式
        if self.match_case:
            pattern = re.escape(self.find_pattern)
        else:
            pattern = re.escape(self.find_pattern)
            text_content_lower = text_content.lower()
            find_pattern_lower = self.find_pattern.lower()
        
        # 计算起始位置的偏移量
        start_index = self.text_area.index(start_pos)
        start_line, start_col = map(int, start_index.split('.'))
        start_offset = 0
        
        # 计算从开始到起始位置的字符数
        for i in range(1, start_line):
            line_end = self.text_area.index(f"{i}.end")
            line_length = int(line_end.split('.')[1]) + 1  # +1 是因为包含换行符
            start_offset += line_length
        start_offset += start_col
        
        # 执行查找
        found = False
        if self.match_case:
            match = re.search(pattern, text_content[start_offset:])
        else:
            match = re.search(pattern, text_content_lower[start_offset:], re.IGNORECASE)
        
        if match:
            # 计算匹配位置
            start = start_offset + match.start()
            end = start_offset + match.end()
            
            # 将偏移量转换为文本索引
            current_offset = 0
            start_index = "1.0"
            end_index = "1.0"
            
            line = 1
            while True:
                line_end = self.text_area.index(f"{line}.end")
                line_length = int(line_end.split('.')[1]) + 1  # +1 是因为包含换行符
                
                if current_offset + line_length > start:
                    col = start - current_offset
                    start_index = f"{line}.{col}"
                    break
                    
                current_offset += line_length
                line += 1
                
                # 防止无限循环
                if line > 100000:  # 限制最大行数
                    break
            
            line = 1
            current_offset = 0
            while True:
                line_end = self.text_area.index(f"{line}.end")
                line_length = int(line_end.split('.')[1]) + 1  # +1 是因为包含换行符
                
                if current_offset + line_length > end:
                    col = end - current_offset
                    end_index = f"{line}.{col}"
                    break
                    
                current_offset += line_length
                line += 1
                
                # 防止无限循环
                if line > 100000:  # 限制最大行数
                    break
            
            # 选中找到的文本
            self.text_area.tag_add(tk.SEL, start_index, end_index)
            self.text_area.mark_set(tk.INSERT, end_index)
            self.text_area.see(tk.INSERT)
            self.find_pos = end_index
            found = True
        else:
            # 如果没找到且不是自动替换模式，提示用户
            if not automatic:
                messagebox.showinfo("查找完成", f"找不到 '{self.find_pattern}'")
                self.find_pos = "1.0"  # 回到开始位置
        
        return found

    # 格式调整功能实现
    def apply_format(self, format_type):
        """应用文本格式（加粗、斜体等）"""
        try:
            # 获取选中的文本范围
            start = self.text_area.index(tk.SEL_FIRST)
            end = self.text_area.index(tk.SEL_LAST)
            
            # 检查是否已有该格式
            current_tags = self.text_area.tag_names(f"{start}+1c")
            
            # 根据格式类型设置或移除标签
            if format_type in current_tags:
                self.text_area.tag_remove(format_type, start, end)
            else:
                # 确保标签已配置
                if format_type == "bold":
                    self.text_area.tag_configure("bold", font=(self.current_font[0], self.current_font[1], "bold"))
                elif format_type == "italic":
                    self.text_area.tag_configure("italic", font=(self.current_font[0], self.current_font[1], "italic"))
                elif format_type == "underline":
                    self.text_area.tag_configure("underline", underline=True)
                elif format_type == "overstrike":
                    self.text_area.tag_configure("overstrike", overstrike=True)
                
                self.text_area.tag_add(format_type, start, end)
            
            self.saved = False
        except tk.TclError:
            messagebox.showinfo("提示", "请先选中要设置格式的文本")

    def set_font(self):
        """设置字体、字号和样式"""
        # 创建字体设置窗口
        font_window = tk.Toplevel(self.root)
        font_window.title("字体设置")
        font_window.geometry("400x300")
        font_window.transient(self.root)
        font_window.resizable(False, False)
        font_window.config(bg='#F0F0F0')
        
        # 字体选择
        ttk.Label(font_window, text="字体:").grid(row=0, column=0, sticky=tk.W, padx=10, pady=10)
        font_families = sorted([f for f in tkfont.families() if 'sim' in f.lower() or 'microsoft' in f.lower() or 'song' in f.lower()])
        font_var = tk.StringVar(value=self.current_font[0])
        font_combo = ttk.Combobox(font_window, textvariable=font_var, values=font_families, width=25)
        font_combo.grid(row=0, column=1, padx=10, pady=10)
        
        # 字号选择
        ttk.Label(font_window, text="字号:").grid(row=1, column=0, sticky=tk.W, padx=10, pady=10)
        sizes = list(range(8, 73, 2))
        size_var = tk.IntVar(value=self.current_font[1])
        size_combo = ttk.Combobox(font_window, textvariable=size_var, values=sizes, width=10)
        size_combo.grid(row=1, column=1, padx=10, pady=10)
        
        # 字体样式选择
        ttk.Label(font_window, text="样式:").grid(row=2, column=0, sticky=tk.W, padx=10, pady=10)
        style_frame = ttk.Frame(font_window)
        style_frame.grid(row=2, column=1, sticky=tk.W, padx=10, pady=10)
        
        style_var = tk.StringVar(value=self.current_font[2])
        ttk.Radiobutton(style_frame, text="常规", variable=style_var, value="normal").pack(side=tk.LEFT, padx=5)
        ttk.Radiobutton(style_frame, text="加粗", variable=style_var, value="bold").pack(side=tk.LEFT, padx=5)
        ttk.Radiobutton(style_frame, text="斜体", variable=style_var, value="italic").pack(side=tk.LEFT, padx=5)
        
        # 应用按钮
        def apply_font():
            font_family = font_var.get()
            font_size = size_var.get()
            font_style = style_var.get()
            self.current_font = (font_family, font_size, font_style)
            
            # 更新文本区域字体
            font_config = (font_family, font_size)
            if font_style == "bold":
                font_config = (font_family, font_size, "bold")
            elif font_style == "italic":
                font_config = (font_family, font_size, "italic")
                
            self.text_area.configure(font=font_config)
            
            # 更新格式标签的字体
            self.text_area.tag_configure("bold", font=(font_family, font_size, "bold"))
            self.text_area.tag_configure("italic", font=(font_family, font_size, "italic"))
            
            self.saved = False
            font_window.destroy()
        
        btn_frame = ttk.Frame(font_window)
        btn_frame.grid(row=3, column=0, columnspan=2, pady=20)
        ttk.Button(btn_frame, text="应用", command=apply_font, width=15).pack(side=tk.LEFT, padx=10)
        ttk.Button(btn_frame, text="取消", command=font_window.destroy, width=15).pack(side=tk.LEFT, padx=10)

    def set_color(self):
        """设置文本颜色和背景颜色"""
        # 创建颜色选择窗口
        color_window = tk.Toplevel(self.root)
        color_window.title("颜色设置")
        color_window.geometry("500x400")
        color_window.transient(self.root)
        color_window.config(bg='#F0F0F0')
        
        # 颜色设置选项卡
        notebook = ttk.Notebook(color_window)
        notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 文本颜色选项卡
        fg_frame = ttk.Frame(notebook)
        notebook.add(fg_frame, text="文本颜色")
        
        # 背景颜色选项卡
        bg_frame = ttk.Frame(notebook)
        notebook.add(bg_frame, text="背景颜色")
        
        # 预定义一些常用颜色
        colors = [
            "black", "red", "green", "blue", "cyan", "magenta", "yellow", "white",
            "darkred", "darkgreen", "darkblue", "darkcyan", "darkmagenta", "darkyellow",
            "gray", "darkgray", "lightgray", "pink", "purple", "orange", "brown",
            "#FF4500", "#FFD700", "#32CD32", "#1E90FF", "#9370DB", "#FF69B4", "#20B2AA"
        ]
        
        # 文本颜色选择
        fg_color_var = tk.StringVar(value=self.current_fg_color)
        self.create_color_grid(fg_frame, colors, fg_color_var)
        
        # 背景颜色选择
        bg_color_var = tk.StringVar(value=self.current_bg_color)
        self.create_color_grid(bg_frame, colors, bg_color_var)
        
        # 应用按钮
        def apply_color():
            # 更新文本颜色
            self.current_fg_color = fg_color_var.get()
            # 更新背景颜色
            self.current_bg_color = bg_color_var.get()
            
            # 应用颜色设置
            self.text_area.configure(fg=self.current_fg_color, bg=self.current_bg_color)
            
            self.saved = False
            color_window.destroy()
        
        btn_frame = ttk.Frame(color_window)
        btn_frame.pack(fill=tk.X, padx=10, pady=10)
        ttk.Button(btn_frame, text="应用", command=apply_color, width=15).pack(side=tk.LEFT, padx=10)
        ttk.Button(btn_frame, text="取消", command=color_window.destroy, width=15).pack(side=tk.RIGHT, padx=10)

    def create_color_grid(self, parent, colors, color_var):
        """创建颜色选择网格"""
        # 颜色选择说明
        ttk.Label(parent, text="点击选择颜色:").pack(anchor=tk.W, padx=10, pady=10)
        
        # 颜色网格框架
        color_frame = ttk.Frame(parent)
        color_frame.pack(fill=tk.BOTH, expand=True, padx=10)
        
        # 创建颜色选择网格
        row, col = 0, 0
        for color in colors:
            # 颜色按钮框架
            btn_frame = ttk.Frame(color_frame, width=40, height=40, relief=tk.RAISED, borderwidth=2)
            btn_frame.grid(row=row, column=col, padx=5, pady=5)
            btn_frame.pack_propagate(False)
            
            # 颜色示例
            ttk.Label(btn_frame, background=color).pack(fill=tk.BOTH, expand=True)
            
            # 点击选择颜色
            def select_color(c):
                return lambda: color_var.set(c)
            
            btn_frame.bind("<Button-1>", select_color(color))
            
            col += 1
            if col > 6:  # 每行显示7个颜色
                col = 0
                row += 1

    # 原有功能保持不变
    def new_note(self):
        if not self.saved:
            if messagebox.askyesno("提示", "当前笔记有未保存内容，是否保存？"):
                self.save_note()
        self.text_area.delete(1.0, tk.END)
        self.current_file = None
        self.saved = True
        self.root.title("增强版记事本")

    def new_template_note(self):
        template = simpledialog.askstring("选择模板", "请输入模板类型（待办/日记）：")
        if template:
            if not self.saved:
                if messagebox.askyesno("提示", "当前笔记有未保存内容，是否保存？"):
                    self.save_note()
            self.text_area.delete(1.0, tk.END)
            if template.lower() == "待办":
                self.text_area.insert(tk.END, "## 待办事项\n- [ ] 任务1\n- [ ] 任务2\n")
            elif template.lower() == "日记":
                import datetime
                today = datetime.date.today().strftime("%Y-%m-%d")
                self.text_area.insert(tk.END, f"# {today} 日记\n\n今天发生了...\n")
            self.current_file = None
            self.saved = False
            self.root.title("增强版记事本 - 未保存")

    def open_note(self):
        if not self.saved:
            if messagebox.askyesno("提示", "当前笔记有未保存内容，是否保存？"):
                self.save_note()
        file_path = filedialog.askopenfilename(
            filetypes=[("文本文件", "*.txt"), ("Markdown文件", "*.md"), ("HTML文件", "*.html"), ("所有文件", "*.*")]
        )
        if file_path:
            self.current_file = file_path
            with open(file_path, "r", encoding="utf-8") as file:
                content = file.read()
                self.text_area.delete(1.0, tk.END)
                self.text_area.insert(tk.END, content)
            self.saved = True
            self.root.title(f"增强版记事本 - {os.path.basename(file_path)}")

    def save_note(self):
        if self.current_file:
            content = self.text_area.get(1.0, tk.END)
            with open(self.current_file, "w", encoding="utf-8") as file:
                file.write(content)
            self.saved = True
            self.root.title(f"增强版记事本 - {os.path.basename(self.current_file)}")
        else:
            self.save_note_as()

    def save_note_as(self):
        file_types = [
            ("文本文件", "*.txt"),
            ("Markdown文件", "*.md"),
            ("HTML文件", "*.html")
        ]
        file_path = filedialog.asksaveasfilename(filetypes=file_types)
        if file_path:
            content = self.text_area.get(1.0, tk.END)
            with open(file_path, "w", encoding="utf-8") as file:
                file.write(content)
            self.current_file = file_path
            self.saved = True
            self.root.title(f"增强版记事本 - {os.path.basename(file_path)}")

    def on_text_change(self, event):
        self.saved = False
        if self.current_file:
            self.root.title(f"增强版记事本 - {os.path.basename(self.current_file)} *")
        else:
            self.root.title("增强版记事本 - 未保存 *")

    def exit_app(self):
        if not self.saved:
            if messagebox.askyesno("提示", "当前笔记有未保存内容，是否保存？"):
                self.save_note()
        self.root.destroy()

if __name__ == "__main__":
    root = tk.Tk()
    # 设置窗口图标（根据实际路径修改）
    # root.iconbitmap('favicon.ico')
    app = NotePad(root)
    root.mainloop()
